<template>
  <div class="container">
    <div class="bg-white ptb-30">
      <van-skeleton title :row="5" :loading="loading" />
    </div>
    <div
      v-for="page in pages"
      :key="page"
      ref="pageContainer"
      :style="{
        borderBottom: '1px solid #DFDFDF',
      }"
    >
      <canvas v-if="renderList.includes(page)"></canvas>
    </div>
  </div>
</template>

<script>
import pdfJS from "pdfjs-dist";
export default {
  props: {
    url: {
      type: String,
      required: true
    },
    manualRender: {
      type: Boolean,
      default: false
    },
    renderPages: {
      // 前后各预渲染多少页
      type: Number,
      default: 5
    },
    showPageLine: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      loading: true,
      pdfDoc: null,
      pages: 0,
      currentPage: 0,
      pageHeight: 0,
      renderList: [], // 渲染的页码数组
      timerIndex: 0
    };
  },
  watch: {
    url() {
      this.getPDFFile();
    }
  },
  created() {
    // 加载loading
    this.$toast.loading({
      duration: 0,
      loadingType: "spinner",
      message: "loading..."
    });
    this.getPDFFile();
    if (!this.manualRender) {
      document.addEventListener("scroll", this.documentScroll);
    }
  },
  beforeDestroy() {
    document.removeEventListener("scroll", this.documentScroll);
    this.timerIndex && clearTimeout(this.timerIndex);
  },
  methods: {
    getPDFFile() {
      if (!this.url) return;
      pdfJS.getDocument(this.url).then(pdf => {
        this.pdfDoc = pdf;
        this.pages = this.pdfDoc.numPages;
        this.$nextTick(() => {
          this.pages && this.scrollToPage(1);
        });
      });
    },
    scrollToPage(pageNo) {
      if (this.currentPage === pageNo) return;
      this.currentPage = pageNo;
      let list = [];
      for (
        let page = pageNo - this.renderPages;
        page <= pageNo + this.renderPages;
        page++
      ) {
        list.push(page);
      }
      for (let idx = list.length; idx >= 0; idx--) {
        if (list[idx] > this.pages || list[idx] < 1) list.splice(idx, 1);
      }
      this.$nextTick(() => {
        this.renderList = list;
        this.renderList.forEach(page => {
          this.renderPage(page);
        });
      });
    },
    renderPage(pageNo) {
      this.pdfDoc.getPage(pageNo).then(page => {
        let containerNode = this.$refs.pageContainer[pageNo - 1];
        if (!containerNode) return;
        let canvas = containerNode.querySelector("canvas");
        if (!canvas || canvas.__rendered) return;
        let ctx = canvas.getContext("2d");
        let dpr = window.devicePixelRatio || 1;
        let bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1;
        let ratio = dpr / bsr;
        let viewport = page.getViewport(
          screen.availWidth / page.getViewport(0.5).width
        );
        canvas.width = viewport.width * ratio;
        canvas.height = viewport.height * ratio;
        // canvas.style.width = viewport.width + "px";
        // canvas.style.height = viewport.height + "px";
        this.pageHeight = viewport.height;
        ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
        let renderCtx = {
          canvasContext: ctx,
          viewport
        };
        page.render(renderCtx);
        canvas.__rendered = true;
        // 载入成功，清除toast和骨架屏
        this.$toast.clear();
        this.loading = false;
      });
    },
    documentScroll() {
      this.checkRender();
    },
    checkRender() {
      this.timerIndex && clearTimeout(this.timerIndex);
      this.timerIndex = setTimeout(this.renderCurrent, 100);
    },
    renderCurrent() {
      this.$nextTick(() => {
        if (this.pages <= 0) return;
        if (!this.pageHeight) return;
        if (!this.$refs.pageContainer[0]) return;
        let rect = this.$refs.pageContainer[0].getBoundingClientRect();
        if (rect.top >= 0) {
          this.scrollToPage(1);
        } else {
          let page = Math.floor(-rect.top / this.pageHeight) + 1;
          if (page > this.pages) page = this.pages;
          this.scrollToPage(page);
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped>
canvas {
  width: 100%;
}
</style>